/**
 * Created by TangZK on 2015/5/13.
 */
(function (root, $, audiojs) {
	var socket;
	var conf_server = conf["server"];

	// TODO from server to get avatar
	var getAvatar = function (uid) {
		return 'asset/avatar/u' + (uid % 11) + '.jpg';
	};

	var Util = {
		friendlyTime: function(timestamp) {
			timestamp = timestamp || 0;
			var ftime,
				date = new Date(),
				now = date.getTime(),
				secFromNow,
				mTimestamp = parseInt(timestamp * 1000) || now;
			secFromNow = now - timestamp;
			var secDay = 3600 * 24;
			if(secFromNow < secDay) {
				ftime = moment(mTimestamp).format('H:mm:ss');
			} else if(date.getFullYear() == moment(mTimestamp).format('YYYY')) {
				ftime = moment(mTimestamp).format('MM-DD H:mm:ss');
			} else {
				ftime = moment(mTimestamp).format('YYYY-MM-DD H:mm:ss');
			}
			return ftime;
		}
	};

	var soundManager = (function() {
		var module = {
			audioHandle: undefined,
			init: function() {
				var me = this;
				audiojs.events.ready(function() {
					me.audioHandle = audiojs.createAll();
				});
			},
			play: function(idx) {
				var me = this;
				idx = idx || 0;
				me.audioHandle[idx].play();
			}
		};
		return module;
	})();

	var socketManager = (function () {
		return {
			start: function () {
				this.socketConnect();
				userManager.init();
			},
			socketConnect: function () {
				var easyChatServ = this.getServerAddr('/easy-chat');
				socket = io.connect(easyChatServ);
			},
			getServerAddr: function (namespace) {
				return conf_server + namespace;
			},
			listen: function () {
				var me = this;
				var myUID = userManager.myInfo.user_id;

				me.onMessage(myUID);
				me.onMessageList(myUID);
				me.onOnlineList();
				me.onUserOnline();
				me.onUserOffline();
				me.onHistoryMessage();
				me.onMessageSendTime();
			},
			onMessage: function (myUID) {
				socket.on('message', function (jsonStr) {
					var jo = JSON.parse(jsonStr),
						userInfo = jo.from,
						msgStr = jo.message,
						fromUid = parseInt(userInfo.user_id);
					if (fromUid === chatManager.currentChatUid) { // 如果聊天对象的窗口已经打开
						var co = {};
						co.avatar = userInfo.avatar;
						co.message = msgStr;
						co.uid = fromUid;
						co.time = Util.friendlyTime();
						co.timestamp = parseInt((new Date()).getTime() / 1000);
						chatManager.showNewMsgList(co);
						chatManager.markMsgStateToRead(myUID, fromUid);
						chatManager.setNewMsgNum(fromUid, 0);
					} else {
						chatManager.addNewMsgNum(fromUid);
					}
					soundManager.play(0);
				});
			},
			onMessageList: function (myUID) {
				// 从服务器端获取到的未读或历史消息列表
				socket.on('msg_list', function (jsonStr) {
					chatManager.setHistoryMsgTrigger();
					if (!myUID) {
						myUID = userManager.myInfo.user_id;
					}
					var jo = JSON.parse(jsonStr);
					if (jo) {
						var flag = jo.flag;
						var arr = jo.result;
						if (myUID == jo.uid && $.isArray(arr)) {
							var arrLen = arr.length;
							if (arrLen > 0) {
								chatManager.showHistoryMsgList(arr);
								if (flag == 1) {
									var liHtml = chatManager.buildTimeSplit(0, '以上是历史消息');
									chatManager.appendToMsgList(liHtml);
								}
								chatManager.markMsgStateToRead(myUID, jo.to_uid);
								chatManager.setNewMsgNum(jo.to_uid, 0);
							}
						}
					}
				});
			},
			onOnlineList: function () {
				// 从服务器端获取在线列表
				socket.on('online_list', function (jsonStr) {
					var jo = JSON.parse(jsonStr);
					if (jo) {
						$('.avabox').removeClass('onLine');
						$.each(jo, function (uid, val) {
							var $uLi = chatManager.getUser$Li(uid);
							chatManager.$userList.prepend($uLi);
							$uLi.find('.avabox').addClass('onLine');
						});
					}
				});
			},
			onUserOffline: function () {
				// 服务器端通知下线
				socket.on('user_offline', function (uid) {
					if (uid) {
						var $uLi = chatManager.getUser$Li(uid);
						$uLi.find('.avabox').removeClass('onLine');
					}
				});
			},
			onUserOnline: function () {
				// 服务器端通知上线
				socket.on('user_online', function (uid) {
					if (uid) {
						var $uLi = chatManager.getUser$Li(uid);
						chatManager.$userList.prepend($uLi);
						$uLi.find('.avabox').addClass('onLine');
					}
				});
			},
			onHistoryMessage: function () {
				// 获取某用户的历史消息
				socket.on('history_msg', function (jsonStr) {
					var jo = JSON.parse(jsonStr);
					if (jo) {
						var $uLi = chatManager.getUser$Li(jo.chat_uid);
						$uLi.data('page', jo.page);
						if (jo.chat_uid == chatManager.currentChatUid) {
							var liHtml = '';
							var arr = jo.result;
							if ($.isArray(arr)) {
								if (arr.length > 0) {
									chatManager.showHistoryMsgList(arr);
								} else {
									var noMore = '<li class="li ecGetHisLi">';
									noMore += '<div class="tipbox"><span class="nomoretip">没有更多消息</span></div>';
									noMore += '</li>';
									chatManager.$msgList.find('.ecGetHisLi').replaceWith(noMore);
								}
							}
						}
					}
				});
			},
			onMessageSendTime: function () {
				socket.on('msg_send_time', function (jsonStr) {
					var jo = JSON.parse(jsonStr);
					if (jo) {
						var toUID = jo.to_uid,
							$toULi = chatManager.getUser$Li(toUID);
						if (jo.send_time > 0) {
							$toULi.data('send_time', jo.send_time);
						}
					}
				});
			}
		};
	})();

	var chatManager = (function () {
		var module = {
			$ecFold: undefined,
			$ecWin: undefined,
			$msgInput: undefined,
			$msgEmitter: undefined,
			$msgList: undefined,
			$userList: undefined,
			$chatUserName: undefined,
			$ulScroll: undefined,
			$ecToUID: undefined, //聊天窗口中，发送给用户的ID
			$ecDlgBox: undefined,
			chatStaus: 'emptyChatBox', //聊天窗口状态 'emptyChatBox'，'activeChatBox'
			currentChatUid: 0, //正在聊天的用户id
			init: function () {
				this.initView();
				socketManager.listen();
				soundManager.init();
			},
			initView: function () {
				var me = this;
				me.$ecFold = $('#ecFold');
				me.$ecWin = $('#ecWin');
				me.$userList = $('#ecUserList');
				me.$msgInput = $('#ecMsgInput');
				me.$msgEmitter = $('#ecMsgSendBtn');
				me.$msgList = $('#ecMsgList');
				me.$chatUserName = $('#ecChatUserName');
				me.$ecToUID = $('#ecToUID');
				me.$ecDlgBox = $('#ecDlgBox');

				me.$ulScroll = new IScroll('.js-iscroll', {
					mouseWheel: true,
					scrollbars: true
				});
				me.bindShowChatView();
				me.bindHideChatView();
				me.bindMsgEmitter();
				me.bindCloseChatBtn(me.$ecDlgBox);
			},
			/**
			 * @param {{user_id:string}} myInfo
			 */
			emitMsg: function () {
				var me = this,
					msgObj = {},
					myInfo,
					msgStr = me.$msgInput.val();
				myInfo = userManager.myInfo;
				msgObj.message = msgStr;
				msgObj.from = myInfo;
				msgObj.to = this.$ecToUID.val();

				var co = {};
				co.avatar = myInfo.avatar;
				co.message = msgStr;
				co.uid = myInfo.user_id;
				co.time = Util.friendlyTime();
				co.timestamp = parseInt((new Date()).getTime() / 1000);

				me.showNewMsgList(co);
				socket.emit('message', JSON.stringify(msgObj));
				me.cleanMsgIput();
			},
			bindShowChatView: function () {
				var me = this;
				me.$ecFold.find('.js-showChatView').on('click', function () {
					me.$ecFold.hide();
					me.$ecWin.show();
					me.refreshScroll();
				});
			},
			bindHideChatView: function () {
				var me = this;
				me.$ecWin.find('.js-hideChatWin').on('click', function () {
					me.$ecFold.show();
					me.$ecWin.hide();
				});
			},
			bindMsgEmitter: function () {
				var me = this;
				me.$msgEmitter.on('click', function () {
					me.emitMsg();
				});
			},
			appendToMsgList: function (data) {
				var me = this,
					$msgList = me.$msgList,
					liHtml;
				if($.isPlainObject(data)) {
					liHtml = me.buildMsgLi(data);
				} else {
					liHtml = data;
				}
				$msgList.append(liHtml);
				$msgList.animate({scrollTop: $msgList[0].scrollHeight}, 100);
			},
			getMessageObj: function(row) {
				var co = {};
				co.uid = row.uid;
				co.avatar = getAvatar(co.uid);
				co.message = row.message;
				co.time = Util.friendlyTime(row.send_time);
				co.timestamp = row.send_time;
				return co;
			},
			showNewMsgList: function(mo) {
				var me = this,
					$lTL = me.$msgList.find('.ecTimeLi:last'),
					endtime,
					timeSpan = 60 * 5,
					isNeedTimeSplit = 1;
				if($lTL.size() > 0) {
					endtime = $lTL.data('mark');
					if(endtime && (mo.timestamp < endtime + timeSpan)) {
						isNeedTimeSplit = 0;
					}
				}
				var liHtml = '';
				if(isNeedTimeSplit) {
					liHtml += me.buildTimeSplit(mo.timestamp);
					me.appendToMsgList(liHtml);
				}
				me.appendToMsgList(mo);
			},
			showHistoryMsgList: function (arr) {
				var me = this,
					$msgList = me.$msgList,
					liHtmlA = '',
					liHtmlB = '',
					endtime = 0;
				var $fTL = me.$msgList.find('.ecTimeLi:first');
				if($fTL.size() > 0) {
					endtime = $fTL.data('mark');
				}
				var gArr = me.groupMsgByTime(arr, endtime);
				gArr.reverse();
				if(gArr.length > 0) {
					$.each(gArr, function(k, v){
						v.arr.reverse();
						if(v.flag > 0) { //在消息列表里有同一时间段的消息
							$.each(v.arr, function (k, row) {
								var co = me.getMessageObj(row);
								liHtmlA += me.buildMsgLi(co);
							});
						} else {
							liHtmlB += me.buildTimeSplit(v.timestamp);
							$.each(v.arr, function (k, row) {
								var co = me.getMessageObj(row);
								liHtmlB += me.buildMsgLi(co);
							});
						}
					});
					if(liHtmlA && $fTL.size() > 0) {
						$fTL.after(liHtmlA);
					}
					if(liHtmlB) {
						$msgList.find('.ecGetHisLi').after(liHtmlB);
					}
				}
				$msgList.find('.tipbox').removeClass('loadding');
			},
			//将消息按时间分组, 给定的消息数组按send_time降序排列
			groupMsgByTime: function(msgArr, endtime) {
				var _msgArr = [];
				var timeSpan = 60 * 5;
				var getTheGroup = function(timestamp) {
					var group = undefined;
					if(_msgArr.length > 0) {
						$.each(_msgArr, function(k, gro) {
							if(timestamp == gro.timestamp) {
								group = gro;
								return false;
							}
						});
					}
					return group;
				};
				var buildMsgArr = function(mo, flg) {
					var stime = endtime - timeSpan;
					//console.log(mo.send_time +'>'+ stime + '    ' + mo.send_time +'<='+ endtime);
					if(mo.send_time > stime && mo.send_time <= endtime) {
						var obj = getTheGroup(endtime);
						if(obj !== undefined) {
							obj.arr.push(mo);
						} else {
							var _obj = {
								timestamp: endtime,
								arr: [mo],
								flag: flg
							};
							_msgArr.push(_obj);
						}
					} else {
						endtime = mo.send_time;
						buildMsgArr(mo, 0);
					}
				};

				if ($.isArray(msgArr) && msgArr[0] && msgArr[0]['send_time']) {
					endtime = endtime || 0;
					var flg = 1;
					if (endtime <= 0) { // 如果没有指定起始时间，则以消息的第一条时间为基础
						flg = 0;
						endtime = msgArr[0]['send_time'];
					}
					$.each(msgArr, function (k, mo) {
						buildMsgArr(mo, flg);
					});
				}
				return _msgArr;
			},
			//将消息改成已读状态
			markMsgStateToRead: function (readerUID, fromUID) {
				var uo = {};
				uo.uid = readerUID;
				uo.to_uid = fromUID;
				socket.emit('update_msg_state', JSON.stringify(uo));
			},
			setHistoryMsgTrigger: function () {
				var hisViewHtml = this.buildHistoryMsgView();
				if ($('.ecGetHisLi').size() === 0) {
					this.$msgList.prepend(hisViewHtml);
					this.bindGetHistoryMsg();
				}
			},
			buildTimeSplit: function (timestamp, txt) {
				var viewHtml = '<li class="li ecTimeLi';
				if(txt) {
					viewHtml += ' spline';
				} else {
					txt = Util.friendlyTime(timestamp);
				}
				viewHtml += '" data-mark="' + timestamp + '">';
				viewHtml += '<div class="timebox"><span class="tmstr">' + txt + '</span></div>';
				viewHtml += '</li>';
				return viewHtml;
			},
			buildHistoryMsgView: function () {
				var viewHtml = '<li class="li ecGetHisLi">';
				viewHtml += '<div class="tipbox"><i class="loadmsg"></i><span class="mhtri js-getHistoryMsg">查看更多消息</span></div>';
				viewHtml += '</li>';
				return viewHtml;
			},
			buildMsgLi: function (obj) {
				var myUID = userManager.myInfo.user_id;
				var liHtml = '';
				obj.time = obj.time || '';
				if (myUID == obj.uid) {
					liHtml = '<li class="li lirt clearfix" title="' + obj.time + '" data-time="' + obj.timestamp + '"><div class="avabox"><img class="avaimg" src="' + obj.avatar + '" /></div><span class="triangle"></span><div class="msgct">' + obj.message + '</div></li>';
				}
				else {
					liHtml = '<li class="li clearfix" title="' + obj.time + '" data-time="' + obj.timestamp + '"><div class="avabox"><img class="avaimg" src="' + obj.avatar + '" /></div><span class="triangle"></span><div class="msgct">' + obj.message + '</div></li>';
				}
				return liHtml;
			},
			cleanMsgIput: function () {
				this.$msgInput.val('');
			},
			cleanUserList: function () {
				this.$userList.html('');
			},
			bindShowChatWindow: function ($elm) {
				var me = this,
					$chatUserName = me.$chatUserName;
				$elm.find('.js-showChatWindow').on('click', function (evt) {
					var $target = $(evt.currentTarget);
					var fromUID = $target.data('uid'); // 从某人获取的ID
					if (me.currentChatUid != fromUID) {
						me.buildChatWindow();
						var uname = $target.find('.username').text();
						me.currentChatUid = fromUID;
						me.$ecToUID.val(fromUID);
						$chatUserName.html(uname);
						me.setChatBoxState('activeChatBox');
						var myUID = userManager.myInfo.user_id;
						me.pullRecentMsg(myUID, fromUID);
					}
				});
			},
			setChatBoxState: function (status) {
				var me = this;
				switch (status) {
					case 'emptyChatBox':
						this.$ecDlgBox.addClass('emptyChatBox');
						this.$ecDlgBox.removeClass('activeChatBox');
						me.chatStaus = 'emptyChatBox';
						break;
					case 'activeChatBox':
						this.$ecDlgBox.addClass('activeChatBox');
						this.$ecDlgBox.removeClass('emptyChatBox');
						me.chatStaus = 'activeChatBox';
						break;
				}
			},
			buildChatWindow: function () { // 重置聊天窗口
				var me = this;
				me.$ecToUID.val(0);
				me.$msgList.html('');
			},
			bindCloseChatBtn: function ($elm) {
				var me = this;
				$elm.find('.js-closeChatBtn').on('click', function () {
					me.setChatBoxState('emptyChatBox');
					me.currentChatUid = 0;
				});
			},
			showChatFold: function () {
				this.$ecFold.animate({
					top: '0',
					opacity: 1
				}, 382);
			},
			getUser$Li: function (uid) {
				var uLiID = '#ECUL' + uid;
				return $(uLiID);
			},
			addNewMsgNum: function (uid) {
				var me = this,
					msgNum,
					$uLi = me.getUser$Li(uid);
				if ($uLi.size() > 0) {
					msgNum = parseInt($uLi.find('.newMsgNum').text());
					me.setNewMsgNum(uid, ++msgNum);
				}
			},
			setNewMsgNum: function (uid, num) { //为某用户设置新消息的数量
				var me = this,
					$uLi = me.getUser$Li(uid);
				if ($uLi.size() > 0) {
					$uLi.find('.newMsgNum').text(num);
					if (num > 0) {
						if ($uLi.hasClass('ecNoNewMsg')) {
							$uLi.removeClass('ecNoNewMsg');
						}
					} else {
						$uLi.addClass('ecNoNewMsg');
					}
				}
			},
			pullRecentMsg: function (uid, toUid) { // 拉取最近N条消息，如果有未读消息，则
				socket.emit('pull_msg_list', '{"uid":' + uid + ', "to_uid":' + toUid + '}');
			},
			pullOnLineList: function () {
				socket.emit('pull_online_list');
			},
			bindGetHistoryMsg: function () {
				var me = this;
				$('.js-getHistoryMsg').on('click', function () {
					var $this = $(this),
						jo = {};
					$this.closest('.tipbox').addClass('loadding');
					jo.uid = userManager.myInfo.user_id;
					jo.chat_uid = me.currentChatUid;
					var $uLi = me.getUser$Li(jo.chat_uid);
					jo.page = $uLi.data('page') || 1;
					var send_time = $uLi.data('send_time');
					if (send_time > 0) {
						jo.send_time = send_time;
					}
					socket.emit('get_history_msg', JSON.stringify(jo));
				});
			},
			refreshScroll: function () {
				this.$ulScroll && this.$ulScroll.refresh();
			}
		};
		return module;
	})();

	var userManager = (function () {
		var module = {
			url: null,
			$dtd: null,
			myInfo: '', //{user_id, user_name, email}
			init: function () {
				var me = this;
				me.getMyInfo();
			},
			getMyInfo: function () {
				var me = this;
				if (me.url) {
					$.get(me.url, function (resp) {
						if (resp && resp.code === 0) {
							me.myInfo = resp.my;
							var uid = me.myInfo.user_id;
							if (uid) {
								socket.emit('join', uid);
								var friends = resp.friends;
								me.buidlFriendList(friends);
								chatManager.showChatFold();
							}
						}
					}, 'json');
				} else {
					console.log('Get User Info Error!');
				}
			},
			buidlFriendList: function (friends) {
				var me = this,
					$userList = chatManager.$userList;
				chatManager.cleanUserList();
				$.each(friends, function (i, friend) {
					var newMsgNum = friend.new_msg_num || 0;
					var html = '<li class="li clearfix js-showChatWindow';
					if (newMsgNum == 0) {
						html += ' ecNoNewMsg';
					}
					html += '" id="ECUL' + friend.user_id + '" data-uid="' + friend.user_id + '">';
					html += '<div class="avabox"><img class="avaimg grayscale" src="' + friend.avatar + '"/><span class="newMsgNum">' + newMsgNum + '</span></div>';
					html += '<div class="unbox username"><span>' + friend.user_name + '</span></div>';
					html += '</li>';
					$userList.append(html);
				});
				chatManager.bindShowChatWindow($userList);
				chatManager.refreshScroll();
				chatManager.pullOnLineList();
				me.setAvatarState();
			},
			setAvatarState: function () {
				$('.grayscale').gray();
			}
		};
		return module;
	})();

	var bindEnterKey = function () {
		document.onkeydown = function (event) {
			var e = event || window.event;
			if (e && e.keyCode == 13) {
				chatManager.emitMsg();
			}
		}
	};

	var EasyChat = (function () {
		var defaults;
		defaults = {};
		function Plugin(options) {
			if (options.user_info_url) {
				userManager.url = options.user_info_url;
			}
			this.options = $.extend(true, {}, defaults, options);
			this.init();
		}

		return Plugin;
	})();

	EasyChat.prototype.init = function () {
		this.loadTpl();
	};

	EasyChat.prototype.loadTpl = function () {
		var opt = this.options;
		if (opt && opt.url) {
			if ($('.easyChat').size() === 0) {
				$.get(opt.url, function (tpl) {
					$('body').append(tpl);
					setTimeout(function () {
						socketManager.start();
						chatManager.init();
						bindEnterKey();
					}, 0);
				}, 'html');
			}
		} else {
			console.log('Get The Template Error!');
		}
	};

	$.extend({
		easychat: function (options) {
			if ($('body').data('ec-state') !== 'ready') {
				$('body').data('ec-state', 'ready');
				return new EasyChat(options);
			}
		}
	});

})(window, jQuery, audiojs);
